﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;

namespace RegeditNavigator.SingleInstance
{
    public static class AppSingleton
    {
        private const string GUID = "{7A3823F1-C72F-467B-B55B-7124767A1ABC}";
        private const string Suffix = ".WindowHandle";
        static readonly Mutex Mutex = new Mutex(true, GUID);

        public static void CheckForAnotherInstance()
        {
            if (Mutex.WaitOne(TimeSpan.Zero, true)) return;

            var handle = GetMainWindowHandleOfAnotherProcess();

            if (handle != IntPtr.Zero)
            {
                NativeMethods.ShowWindow(handle, 1);
                NativeMethods.ShowWindow(handle, 9);
                NativeMethods.SendMessage(handle, NativeMethods.WM_SHOWWINDOW, IntPtr.Zero, new IntPtr(NativeMethods.SW_PARENTOPENING));
                NativeMethods.SetForegroundWindow(handle);
            }
            
            Application.Current.Shutdown();
        }

        public static void WriteMainWindowHandle(IntPtr handle)
        {
            var fileHandle = NativeMethods.CreateFileMapping(new IntPtr(-1), IntPtr.Zero, NativeMethods.FileMapProtection.PageReadWrite, 0, 8, GUID + Suffix);
            
            if (fileHandle == IntPtr.Zero) return;

            var viewHandle = NativeMethods.MapViewOfFile(fileHandle, NativeMethods.FileMapAccess.FileMapWrite, 0, 0, new UIntPtr(8));

            if (viewHandle == IntPtr.Zero) return;
            
            Marshal.WriteIntPtr(viewHandle, handle);

            NativeMethods.UnmapViewOfFile(viewHandle);

//            NativeMethods.CloseHandle(viewHandle);
        }

        private static IntPtr GetMainWindowHandleOfAnotherProcess()
        {
            var fileHandle = NativeMethods.OpenFileMapping((int) FileAccess.Read, false, GUID + Suffix);
            
            if (fileHandle == IntPtr.Zero) return IntPtr.Zero;

            var viewHandle = NativeMethods.MapViewOfFile(fileHandle, NativeMethods.FileMapAccess.FileMapRead, 0, 0, new UIntPtr(8));

            if (viewHandle == IntPtr.Zero) return IntPtr.Zero;

            var windowHandle = Marshal.ReadIntPtr(viewHandle);

            // there is no need to close any handles here because the current process will be destroyed anyway.

            return windowHandle;
        }
    }
}
